
const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");
puppeteer.use(StealthPlugin());
const dayjs = require("dayjs");
const userDataDir = process.env.WEB_CONFIG_USER_DATA_DIR;
const executablePath = process.env.WEB_CONFIG_EXECUTABLE_PATH;
const logger = require("../../utils/logger");
const notification = require("../../utils/notification");
const { sendWechatMessage } = require("../../utils");
const axios = require("axios");
const path = require("path");
const fs = require("fs");
// const { publishCallback } = require("../../utils/");
const { saveMysql } = require("../../utils/saveMysql");

const KUAISHOUHAO_USERNAME = process.env.KUAISHOUHAO_USERNAME;
const KUAISHOUHAO_PASSWORD = process.env.KUAISHOUHAO_PASSWORD;
async function getArticlesInfo(params) {
  const browser = await puppeteer.launch({
    headless: "new",
    headless: false,
    executablePath,
    userDataDir,
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-features=site-per-process",
      "--start-maximized",
    ],
    ignoreHTTPSErrors: true,
  });
  try {
    const page = await browser.newPage();
    await page.goto("https://cp.kuaishou.com/article/manage/video", {
      waitUntil: "networkidle0",
    });
    if (await isNotLogin(page)) {
      logger.info("未登录");
      await toLoginPage(page);
      await login(page);
    }
    logger.info("已登录");
    //选择日期
    const startDate = calculateStartDate(params);
    // 选择日期
    const response = await selectDate(page, startDate);
    let data = response.data;

    let articles = [];
    let hasMoreData = true;
    while (hasMoreData) {
      articles = articles.concat(parseArticles(data.list));
      if (data.total > articles.length) {
        // 滚动加载更多数据
        await new Promise((resolve) => setTimeout(resolve, 3000));
        data = await scrollAndFetchMoreData(page);
      } else {
        hasMoreData = false;
        logger.info("已获取所有数据");
      }
    }
    logger.info(`共获取到 ${articles.length} 条数据`);
    return articles;
  } catch (error) {
    logger.error(`获取数据失败: ${error.message}`);
    return [];
  } finally {
    // 关闭浏览器
    await browser.close();
  }
}

async function scrollAndFetchMoreData(page) {
  logger.info("滚动加载更多数据");
  await page.evaluate(() => {
    const container = document.getElementById("main-container");
    if (container) {
      container.scrollTop = container.scrollHeight;
    }
  });

  // 等待并拦截新的数据请求
  const response = await page.waitForResponse((response) =>
    response
      .url()
      .includes("https://cp.kuaishou.com/rest/cp/works/v2/video/pc/photo/list")
  );

  const newData = await response.json();
  logger.info(`获取到新数据: ${newData.data.length || 0}条`);

  return newData.data || 0;
}

function parseArticles(list) {
  return list.map((item) => ({
    title: item.title,
    id: item.workId,
    detail_url: `https://www.kuaishou.com/short-video/${item.workId}`,
    cover: JSON.stringify([item.publishCoverUrl || ""]),
    publish_time: dayjs(item.uploadTime).format("YYYY-MM-DD HH:mm:ss"),
    read_count: item.playCount,
    like_count: item.likeCount,
    comment_count: item.commentCount,
  }));
}

// 检查是否登录
async function isNotLogin(page) {
  try {
    // 等待页面加载完成
    await page.waitForSelector("body", { timeout: 5000 });

    return await page.evaluate(() => {
      // 检查是否出现.login元素
      const loggedInElement = document.querySelector(".login");
      return !!loggedInElement;
    });
  } catch (error) {
    logger.error(`检查登录状态时出错: ${error.message}`);
    return false;
  }
}
// 跳转到登录页面
async function toLoginPage(page) {
  try {
    const loginButton = await page.waitForSelector(".login", { timeout: 5000 });
    if (loginButton) {
      await loginButton.click();
      await page.waitForNavigation({ timeout: 10000 });
    } else {
      throw new Error("未找到登录按钮");
    }
  } catch (error) {
    logger.error(`登录失败: ${error.message}`);
    throw error;
  }
}
// 登录,
async function login(page) {
  try {
    await page.evaluate(() => {
      const link = Array.from(
        document.querySelectorAll("div[class*='tabs-wrapper'] span")
      ).find((span) => span.textContent.includes("密码登录"));
      if (link) {
        link.click();
        console.log("通过 JavaScript 点击了 '密码登录' 链接");
      } else {
        console.warn("在 JavaScript 中未找到 '密码登录' 链接");
      }
    });
    const usernameInput = await page.waitForSelector(
      'input.pl-input-text[placeholder="请输入手机号"]',
      {
        timeout: 5000,
      }
    );
    const passwordInput = await page.waitForSelector(
      'input.pl-input-text[placeholder="请输入密码"]',
      {
        timeout: 5000,
      }
    );
    const loginButton = await page.waitForSelector(".pl-btn", {
      timeout: 5000,
    });

    if (usernameInput && passwordInput && loginButton) {
      logger.info("快手号，开始输入用户名");
      await usernameInput.type(KUAISHOUHAO_USERNAME, { delay: 100 });
      logger.info("快手号，开始输入密码");
      await passwordInput.type(KUAISHOUHAO_PASSWORD, { delay: 100 });
      logger.info("快手号，开始点击登录");
      await loginButton.click();
      await page.waitForNavigation({ timeout: 10000 });
      logger.info("登录成功");
    } else {
      logger.error("未找到登录元素");
      throw new Error("未找到登录元素");
    }
  } catch (error) {
    logger.error(`登录失败: ${error.message}`);
    throw error;
  }
}
//计算startDate
function calculateStartDate(params) {
  if (params.update_type === "highFrequency") {
    return dayjs().subtract(7, "day").format("YYYY-MM-DD");
  } else if (params.interval) {
    const days = parseInt(params.interval);
    return dayjs().subtract(days, "day").format("YYYY-MM-DD");
  } else {
    return dayjs("2024-01-01").format("YYYY-MM-DD");
  }
}
//选择日期
async function selectDate(page, startDate) {
  const endDate = dayjs().format("YYYY-MM-DD");
  try {
    // 等待日期选择器出现
    await page.waitForSelector(".el-date-editor", { timeout: 10000 });

    // 使用 type 方法填充日期
    const inputs = await page.$$(".el-date-editor input");
    if (inputs.length >= 2) {
      await inputs[0].click({ clickCount: 3 });
      await inputs[0].type(startDate, { delay: 100 });
      await inputs[1].click({ clickCount: 3 });
      await inputs[1].type(endDate, { delay: 100 });
    }

    // 点击回车
    await page.keyboard.press("Enter");

    // 等待页面请求完成，获取数据后返回
    const response = await page.waitForResponse((response) =>
      response
        .url()
        .includes(
          "https://cp.kuaishou.com/rest/cp/works/v2/video/pc/photo/list"
        )
    );
    logger.info("日期选择成功");
    return response.json();
  } catch (error) {
    logger.error(`选择日期失败: ${error.message}`);
    throw error;
  }
}

// 发布
async function publish(params) {
  const browser = await puppeteer.launch({
    headless: "new",
    headless: false,
    executablePath,
    userDataDir,
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-features=site-per-process",
      "--start-maximized",
      // "--auto-open-devtools-for-tabs",
    ],
  });
  try {
    const page = await browser.newPage();
    await page.goto("https://cp.kuaishou.com/article/publish/video?tabType=1", {
      waitUntil: "networkidle2",
    });
    logger.info("开始检查是否登录");
    if (await isNotLogin(page)) {
      logger.info("未登录");
      await toLoginPage(page);
      await login(page);
    }
    logger.info("已登录");
    // 下载 params 里面的视频
    const videoPath = await downloadVideo(page, params.video);
    // 下载封面
    const coverPath = await downloadCover(page, params.cover);
    // 上传视频
    await uploadVideo(page, videoPath);
    // 上传封面
    await uploadCover(page, coverPath);
    // 输入视频描述
    await inputVideoDesc(page, params.summary);
    // 输入话题
    await inputTopic(page, params.talk);
    // @用户
    await inputAtUser(page, params.at_users);
    // 个性化设置
    await inputCustomSetting(page, params.custom_setting);
    // permission 查看权限设置
    await inputPermission(page, params.permission);
    // 作者声明
    await inputAuthorStatement(page, params.author_statement);
    // 点击发布按钮 2024-09-16 改版
    // const publishButton = await page.waitForSelector("button[class*='_ok_']");
    // if (publishButton) {
    //   await publishButton.click();
    // }
    // _edit-section-btns_
    await page.evaluate(() => {
      const publishButton = document.querySelectorAll(
        "div[class*='_edit-section-btns_'] div"
      );
      Array.from(publishButton).forEach((button) => {
        if (button.textContent.includes("发布")) {
          button.click();
        }
      });
    });
    // 等待发布成功，监测网络请求，https://cp.kuaishou.com/rest/cp/works/v2/video/pc/publish/refresh， 返回数据 data.list.length > 0, 返回list[0].workId
    const workId = await handlePublishSuccess(page);
    logger.info(`发布成功，作品ID: ${workId}`);
    return workId;
  } catch (error) {
    logger.error(`发布失败: ${error.message}`);
    throw error;
  } finally {
    // 关闭浏览器
    await browser.close();
  }
}
// 下载视频
async function downloadVideo(page, videoUrl) {
  try {
    const date = dayjs().format("YYYY-MM-DD");
    const dir = path.join(__dirname, `../uploads/kuaishouhao/${date}`);
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
      logger.info(`创建目录: ${dir}`);
    }
    // 获取视频文件名
    const videoName = path.basename(new URL(videoUrl).pathname);
    const videoPath = path.join(dir, videoName);
    logger.info(`下载视频: ${videoPath}`);
    // 下载视频
    const response = await axios({
      method: "get",
      url: videoUrl,
      responseType: "stream",
    });
    // 写入视频
    const writer = fs.createWriteStream(videoPath);
    response.data.pipe(writer);

    return new Promise((resolve, reject) => {
      writer.on("finish", () => {
        logger.info(`视频下载完成: ${videoPath}`);
        resolve(videoPath);
      });
      writer.on("error", (error) => {
        logger.error(`视频下载失败: ${error.message}`);
        reject(error);
      });
    });
  } catch (error) {
    logger.error(`下载视频失败: ${error.message}`);
    throw error;
  }
}
// 上传视频
async function uploadVideo(page, videoPath) {
  try {
    const input = await page.waitForSelector(
      "div[id='rc-tabs-0-panel-1'] input[accept*='video']"
    );
    if (input) {
      logger.info(`上传视频开始：${videoPath}`);
      await input.uploadFile(videoPath);
      await page.waitForResponse((response) =>
        response
          .url()
          .includes(
            "https://cp.kuaishou.com/rest/cp/works/v2/video/pc/upload/finish"
          )
      );
      await new Promise((resolve) => setTimeout(resolve, 5000));
      logger.info(`视频上传成功`);
    }
  } catch (error) {
    logger.error(`上传视频失败: ${error.message}`);
    throw error;
  }
}
// 下载封面
async function downloadCover(page, coverUrl) {
  try {
    const date = dayjs().format("YYYY-MM-DD");
    const dir = path.join(__dirname, `../uploads/kuaishouhao/${date}`);
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
      logger.info(`创建目录: ${dir}`);
    }
    // 获取封面文件名
    const coverName = path.basename(new URL(coverUrl).pathname);
    const coverPath = path.join(dir, coverName);
    logger.info(`下载封面: ${coverPath}`);
    // 下载封面
    const response = await axios({
      method: "get",
      url: coverUrl,
      responseType: "stream",
    });
    // 写入封面
    const writer = fs.createWriteStream(coverPath);
    response.data.pipe(writer);

    return new Promise((resolve, reject) => {
      writer.on("finish", () => {
        logger.info(`封面下载完成: ${coverPath}`);
        resolve(coverPath);
      });
      writer.on("error", (error) => {
        logger.error(`封面下载失败: ${error.message}`);
        reject(error);
      });
    });
  } catch (error) {
    logger.error(`下载封面失败: ${error.message}`);
    throw error;
  }
}
// 上传封面
async function uploadCover(page, coverPath) {
  try {
    // await page.evaluate(() => {
    //   const editButton = document.querySelectorAll(
    //     ".ant-tabs-tabpane-active button"
    //   );
    //   Array.from(editButton).forEach((button) => {
    //     if (button.textContent.includes("编辑封面")) {
    //       button.click();
    //     }
    //   });
    // });
    // 2024-09-16 上传图片改版
    await page.evaluate(() => {
      const editButton = document.querySelectorAll(
        'span[class*="_cover-editor-text_"]'
      );
      Array.from(editButton).forEach((button) => {
        if (button.textContent.includes("替换")) {
          button.click();
        }
      });
    });
    await new Promise((resolve) => setTimeout(resolve, 5000));
    // await page.evaluate(() => {
    //   const btns = document.querySelectorAll(".ant-tabs-tab-btn");
    //   Array.from(btns).forEach((btn) => {
    //     if (btn.textContent.includes("上传封面")) {
    //       btn.click();
    //     }
    //   });
    // });
    // await new Promise((resolve) => setTimeout(resolve, 2000));
    const input = await page.waitForSelector(
      ".ant-modal-content input[type='file']"
    );
    if (input) {
      await input.uploadFile(coverPath);
      await new Promise((resolve) => setTimeout(resolve, 5000));
      // 点击确定,2024-09-16 上传图片改版
      // const confirmButton = await page.waitForSelector("button[class*='_ok_']");
      // if (confirmButton) {
      //   await confirmButton.click();
      // }
      await page.evaluate(() => {
        const confirmButton = document.querySelectorAll(
          ".ant-modal-content button"
        );
        Array.from(confirmButton).forEach((button) => {
          if (button.textContent.includes("完成")) {
            button.click();
          }
        });
      });
      await new Promise((resolve) => setTimeout(resolve, 3000));
      logger.info(`封面上传成功`);
    }
  } catch (error) {
    logger.error(`上传封面失败: ${error.message}`);
    throw error;
  }
}
// 输入视频描述, div[class*='_description_'], 是div设置了contenteditable="true",用type输入
async function inputVideoDesc(page, desc) {
  try {
    const input = await page.waitForSelector("div[class*='_description_']");
    if (input) {
      await input.focus();
      await input.type(desc, { delay: 100 });
    }
  } catch (error) {
    logger.error(`输入视频描述失败: ${error.message}`);
    throw error;
  }
}
// 输入话题, 话题要是数组，循环数组，点击#话题按钮，然后输入话题，等待自动搜索下拉话题，点击选中第一个
async function inputTopic(page, topics) {
  logger.info(`准备输入话题: ${topics}`);
  if (!Array.isArray(topics) || topics.length === 0) {
    return;
  }

  for (let topic of topics) {
    logger.info(`开始处理话题: ${topic}`);

    // 点击话题按钮 2024-09-16 改版
    // const topicButton = await page.waitForSelector(
    //   "span[class*='_quick-tips-topic_']"
    // );
    // if (topicButton) {
    //   await topicButton.click();
    //   logger.info("点击了话题按钮");
    // }
    // await new Promise((resolve) => setTimeout(resolve, 2000));

    const input = await page.waitForSelector("div[class*='_description_']");
    if (input) {
      await input.focus();
      // 使用 shift + 3 输入 #
      await page.keyboard.down("Shift");
      await page.keyboard.press("Digit3");
      await page.keyboard.up("Shift");
      await new Promise((resolve) => setTimeout(resolve, 1000));
      await input.type(topic, { delay: 100 });
      await new Promise((resolve) => setTimeout(resolve, 2000));
      // 输入完回车
      await page.keyboard.press("Enter");
    }
    logger.info(`已输入话题: ${topic}`);

    await new Promise((resolve) => setTimeout(resolve, 2000));
    // try {
    //   const topicItem = await page.waitForSelector(
    //     "div[class*='_topic-item_']",
    //     { timeout: 5000 }
    //   );
    //   if (topicItem) {
    //     await topicItem.click();
    //     logger.info(`成功选择话题: ${topic}`);
    //   }
    // } catch (error) {
    //   logger.warn("话题列表为空");
    // }
  }
}
// @用户
async function inputAtUser(page, atUser) {
  logger.info(`准备输入@用户: ${atUser}`);
  if (!Array.isArray(atUser) || atUser.length === 0) {
    return;
  }
  for (let user of atUser) {
    logger.info(`开始处理@用户: ${user}`);
    // 点击@用户按钮 2024-09-16 改版
    // const atUserButton = await page.waitForSelector(
    //   "span[class*='_quick-tips_']"
    // );
    // if (atUserButton) {
    //   await atUserButton.click();
    //   logger.info("点击了@用户按钮");
    // }
    // await new Promise((resolve) => setTimeout(resolve, 2000));
    const input = await page.waitForSelector("div[class*='_description_']");
    if (input) {
      await input.focus();
      // 使用 shift + 2 输入 @
      await page.keyboard.down("Shift");
      await page.keyboard.press("Digit2");
      await page.keyboard.up("Shift");
      await new Promise((resolve) => setTimeout(resolve, 1000));
      await input.type(user, { delay: 100 });
      await new Promise((resolve) => setTimeout(resolve, 2000));
      // 输入完回车
      await page.keyboard.press("Enter");
    }
    await new Promise((resolve) => setTimeout(resolve, 2000));
    // try {
    //   const userList = await page.waitForSelector(
    //     "div[class*='_at-user-container_']",
    //     { timeout: 5000 }
    //   );
    //   if (userList) {
    //     await userList.click();
    //     logger.info(`成功选择@用户: ${user}`);
    //   }
    // } catch (error) {
    //   logger.warn("@用户列表为空");
    //   await input.focus();
    //   await input.type(" ", { delay: 100 });
    // }

    // await new Promise((resolve) => setTimeout(resolve, 2000));
  }
}
// 个性化设置(2024-09-16 改版叫互动设置)
//"custom_setting":["allowSameFrame"],//allowSameFrame 允许别人跟拍我的作品 downloadType 不允许下载此作品 disableNearbyShow 作品在同城不显示
async function inputCustomSetting(page, customSetting) {
  logger.info(`准备输入个性化设置: ${JSON.stringify(customSetting)}`);
  // 根据传入的customSetting，循环点击，找到input value 对应为 item的，选中，其它的都取消选中，如果没有就都取消选中
  await page.evaluate(() => {
    const inputs = document.querySelectorAll(
      "div[class*='ant-checkbox-group'] .ant-checkbox-input"
    );
    console.log("input", inputs);
    // 应该点击取消选中
    Array.from(inputs).forEach((input) => {
      // 取消选中
      if (input.checked) {
        input.click();
      }
    });
  });
  if (!Array.isArray(customSetting) || customSetting.length === 0) return;
  logger.info(`已输入个性化设置: ${JSON.stringify(customSetting)}`);
  for (let item of customSetting) {
    await page.evaluate((item) => {
      const inputs = document.querySelectorAll(
        "div[class*='ant-checkbox-group'] .ant-checkbox-input"
      );
      Array.from(inputs).forEach((input) => {
        if (input.value == item) {
          input.click();
        }
      });
    }, item);
  }
}
// 查看权限设置, 单选框 1，4，2
async function inputPermission(page, permission) {
  logger.info(`准备输入查看权限设置: ${permission}`);
  if (!permission || permission == 1) {
    return;
  }

  await page.evaluate((permissionValue) => {
    const items = document.querySelectorAll('div[class*="_edit-form-item_"]');
    items.forEach((item) => {
      if (item.textContent.includes("查看权限")) {
        const radios = item.querySelectorAll('input[type="radio"]');
        radios.forEach((radio) => {
          if (radio.value == permissionValue) {
            radio.click();
          }
        });
      }
    });
  }, permission);

  logger.info(`已设置查看权限: ${permission}`);
}
// 作者声明 0 1 2 3
async function inputAuthorStatement(page, authorStatement) {
  logger.info(`准备输入作者声明: ${authorStatement}`);
  if (!authorStatement && authorStatement !== 0) return;
  if (authorStatement == 9999) return;
  //滚动页面到底部
  await page.evaluate(() => {
    const container = document.getElementById("main-container");
    if (container) {
      container.scrollTop = container.scrollHeight;
    }
  });
  await new Promise((resolve) => setTimeout(resolve, 2000));
  // 2024-10-24 改版 作者声明改版 id 由 rc_select_0 改为 rc_select_5，不能判断id
  // const select = await page.waitForSelector("#rc_select_0");
  // if (select) {
  //   await select.click();
  //   await new Promise((resolve) => setTimeout(resolve, 2000));
  //   await page.evaluate((authorStatement) => {
  //     const items = Array.from(
  //       document.querySelectorAll('div[class*="_edit-form-item_"]')
  //     );
  //     const authorStatementItem = items.find((item) =>
  //       item.textContent.includes("作者声明")
  //     );
  //     const options = authorStatementItem.querySelectorAll(
  //       'div[class*="ant-select-item"]'
  //     );
  //     // 第 authorStatement 个选项
  //     options[authorStatement].click();
  //   }, authorStatement);
  //   logger.info(`已设置作者声明: ${authorStatement}`);
  // }
  await page.evaluate((authorStatement) => {
    const items = Array.from(
      document.querySelectorAll('div[class*="_edit-form-item_"]')
    );
    const authorStatementItem = items.find((item) =>
      item.textContent.includes("作者声明")
    );
    // 获取input，点击触发下拉
    const input = authorStatementItem.querySelector("input");
    input.click();
    const options = authorStatementItem.querySelectorAll(
      'div[class*="ant-select-item"]'
    );
    // 第 authorStatement 个选项
    options[authorStatement].click();
  }, authorStatement);
  logger.info(`已设置作者声明: ${authorStatement}`);
}
// 等待发布成功，监测网络请求
async function handlePublishSuccess(page) {
  return new Promise((resolve, reject) => {
    let timeoutId = setTimeout(() => {
      reject(new Error("发布超时，未收到预期的响应"));
    }, 120000); // 设置120秒超时

    page.on("response", async (res) => {
      const url = res.url();
      if (
        url.includes(
          "https://cp.kuaishou.com/rest/cp/works/v2/video/pc/publish/refresh"
        )
      ) {
        try {
          let data = await res.json();
          data = data.data;
          // logger.info(`收到发布响应: ${JSON.stringify(data)}`);

          if (
            data &&
            data.list &&
            data.list.length > 0 &&
            data.list[0].workId
          ) {
            clearTimeout(timeoutId);
            resolve(data.list[0].workId);
          } else {
            // logger.warn(`响应数据结构不符合预期: ${JSON.stringify(data)}`);
          }
        } catch (error) {
          logger.error(`解析响应数据时出错: ${error.message}`);
        }
      }
    });
  });
}

exports.handleCommand = async (command, params, taskId) => {
  switch (command) {
    case "getArticlesInfo":
      const data = await getArticlesInfo(params);
      console.log(data)
      saveKuaishou2Mysql(data)
      return { data };
    case "publish":
      try {
        params.talk = ["测试"]

        const result = await publish(params);

        //await publishCallback(params.post_id, 3, "发布成功", taskId, result);

        return { data: [result] };
      } catch (error) {
        logger.error(error);
        // await publishCallback(params.post_id, 4, error.message, taskId, "");
        return { data: [] };
      }

    // 其他命令...
    default:
      throw new Error("Unsupported command");
  }
};


const saveKuaishou2Mysql = async (data) => {
  try {
    // 确保data是数组
    if (!Array.isArray(data)) {
      logger.error('输入数据不是数组格式');
      return;
    }

    for (const video of data) {
      const saveData = {
        // 平台标识，固定为"kuaishou"
        platform: "kuaishouhao",
        // 视频唯一标识ID
        aweme_id: video.id,
        // 视频创建时间，转换为unix时间戳
        create_time: dayjs(video.publish_time).unix(),
        // 数据爬取时间
        crawl_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),

        // 视频基本信息
        video_desc: video.title,
        video_url: video.detail_url,
        // 解析JSON字符串获取第一个封面URL，如果解析失败则使用空字符串
        cover_url: (() => {
          try {
            const covers = JSON.parse(video.cover);
            return Array.isArray(covers) && covers.length > 0 ? covers[0] : '';
          } catch (e) {
            logger.warn(`解析视频 ${video.id} 的封面URL失败: ${e.message}`);
            return '';
          }
        })(),

        // 统计数据
        play_count: video.read_count || 0,
        digg_count: video.like_count || 0,
        comment_count: video.comment_count || 0,

        // 以下是必需字段但API未提供的数据，设置默认值
        author_uid: '',
        author_sec_uid: '',
        author_nickname: '',
        author_signature: '',
        author_avatar_url: '',
        author_following_count: 0,
        author_follower_count: 0,
        author_total_favorited: 0,
        author_unique_id: '',
        duration: 0,
        width: 0,
        height: 0,
        download_count: 0,
        forward_count: 0,
        share_count: 0,
        music_id: '',
        music_title: '',
        music_author: '',
        music_duration: 0,
        hashtags: '[]'
      };

      logger.info(`正在保存快手视频 ${video.id} 的数据`);
      await saveMysql(saveData);

      // 添加延迟避免请求过快
      await new Promise(resolve => setTimeout(resolve, 1000));
    }

    logger.info(`数据保存完成，共处理 ${data.length} 条记录`);
  } catch (error) {
    logger.error(`保存数据时发生错误: ${error.message}`);
    throw error;
  }
};
